
package com.hlkj.pay.app.merchant.ext.impl.hnapay.ext;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import cn.hutool.core.date.DatePattern;
import cn.hutool.json.JSONObject;
import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.framework.extension.annotation.Extension;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderQueryContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelRefundPayOrderContext;
import com.hlkj.pay.app.merchant.ext.impl.hnapay.HnapayScenePayOrderExtPt;
import com.hlkj.pay.app.merchant.ext.impl.hnapay.constant.HnapayConstant;
import com.hlkj.pay.app.merchant.ext.impl.hnapay.constant.HnapayExtConstant;
import com.hlkj.pay.app.merchant.ext.impl.hnapay.dto.HnapayAppChannelParams;
import com.hlkj.pay.app.merchant.ext.impl.hnapay.dto.HnapayConfig;
import com.hlkj.pay.app.merchant.ext.impl.hnapay.handler.HnapayMerchantCommonParamsHandle;
import com.hlkj.pay.app.merchant.ext.impl.hnapay.utils.HttpUtils;
import com.hlkj.pay.app.merchant.ext.impl.hnapay.utils.RecepitUtil;
import com.hlkj.pay.enums.PayEnums;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAccessAuthDO;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAppChannelDO;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.infrastructure.model.pay.PayWayDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderChannelConfigDO;
import com.hlkj.pay.util.DateUtils;
import com.hlkj.pay.util.MerchantUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriComponentsBuilder;

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 主扫统一下单 用户扫支付码
 *
 * @author HlpayTeam
 * @date 2024/11/18 13:07
 */
@Slf4j
@Repository
@RequiredArgsConstructor
@Extension(bizId = HnapayExtConstant.NATIVE_PAY)
public class HnapayScanPayOrderExtPt extends HnapaySceneCommonPayOrder implements HnapayScenePayOrderExtPt {

    private final HnapayMerchantCommonParamsHandle paramsHandle;

    @Override
    public void submitChannelPayOrder(ChannelPayOrderContext channelPayOrderContext) {
        //消息体加密的字段顺序
        //{ "tranCode", "version", "merId", "submitTime", "merOrderNum", "tranAmt", "payType", "orgCode", "notifyUrl", "charset", "signType" }
        // 配置转换
        ProviderChannelConfigDO providerChannelConfigDO = channelPayOrderContext.getProviderChannelConfigDO();
        String channelConfig = providerChannelConfigDO.getParamsConfig();
        HnapayConfig payConfig = getPayConfig(channelConfig, channelPayOrderContext.getMerchantAppChannelDO());
        PayOrderDO payOrderDO = channelPayOrderContext.getPayOrderDO();
        try {
            MerchantAppChannelDO merchantAppChannelDO = channelPayOrderContext.getMerchantAppChannelDO();
            HnapayAppChannelParams appChannelParams = appChannelParams(merchantAppChannelDO);

            PayWayDO payWayDO = channelPayOrderContext.getPayWayDO();
            String url = domain(channelPayOrderContext.isTest()) + HnapayConstant.TRADE_NATIVE_CREATE;
            Map<String, String> params = new LinkedHashMap<>();
            params.put("tranCode", "WS01"); // 交易代码
            params.put("version", "2.0"); // 版本
            params.put("merId", payConfig.getMerId()); // 商户ID
            params.put("submitTime", DateUtils.getDateString(DatePattern.PURE_DATETIME_PATTERN)); // 提交时间
            params.put("merOrderNum", payOrderDO.getPayOrderNo()); // 商户订单号
            params.put("tranAmt", MerchantUtils.YuanToFen(payOrderDO.getAmount()).toString()); // 商户订单金额
            params.put("payType", "QRCODE_B2C"); // 支付类型：只能为QRCODE_B2C
            params.put("orgCode", getPayType(payWayDO)); // 目标资金机构：WECHATPAY：微信支付；ALIPAY：阿里支付；TENPAY：腾讯支付
            params.put("notifyUrl", channelPayOrderContext.getNotifyUrl()); // 版本
//            params.put("notifyUrl", "https://test-api.hbhlpay.com/applyments.ffpay/asyncReturn");
            params.put("charset", "1"); // 版本
            params.put("signType", "3"); // 版本
            params.put("signMsg", RecepitUtil.sign(payConfig.getMchM2PrivateKey(), params)); // 版本
            params.put("goodsName", payOrderDO.getSubject()); // 商品名称
            params.put("goodsDetail", payOrderDO.getDescription()); // 商品名称
            params.put("tranIP", payOrderDO.getClientIp()); // IP地址

            PayEnums.PAY_TYPE payType = PayEnums.PAY_TYPE.fromByCode(payWayDO.getType());
            MerchantAccessAuthDO merchantAccessAuthDO = paramsHandle.randomMchId(payOrderDO.getMchChannelCode(), payType, appChannelParams);
            if (merchantAccessAuthDO == null) {
                throw new Exception("没有可用的子商户号");
            }
            params.put("weChatMchId", merchantAccessAuthDO.getSerialCode()); // 子商户进件完成后生成的报备编号
            params.put("submitUrl", url);

            log.info("新生支付下单req参数:{}", JsonUtils.toJsonString(params));
            String response = HttpUtils.postForm(url, params);
            log.info("新生支付下单返回参数:{}", response);

            channelPayOrderContext.setAutSubMerId(merchantAccessAuthDO.getSubMchId());
            channelPayOrderContext.setAutCode(merchantAccessAuthDO.getCode());
            JSONObject rspBody =  JsonUtils.parseObj(response);
            if ("0000".equals(rspBody.getStr("resultCode"))) {
                channelPayOrderContext.setPayDataType("pay_url");
                Map<String, String> qrParams = UriComponentsBuilder.fromUriString(rspBody.getStr("qrCodeUrl"))
                        .build()
                        .getQueryParams()
                        .toSingleValueMap();
                channelPayOrderContext.setPayInfo(qrParams.get("qrContent"));
            } else {
                String respDesc = rspBody.getStr("msgExt");
                channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                if (StringUtils.hasText(respDesc)) {
                    channelPayOrderContext.setRemark(respDesc);
                } else {
                    channelPayOrderContext.setRemark("新生支付下单查询返回错误信息为空,错误码为:" + rspBody.getStr("resultCode"));
                }
            }
        } catch (Exception e) {
            log.error("新生支付下单失败 message:{}", e.getMessage(), e);
            channelPayOrderContext.setRemark("新生支付下单失败,失败信息" + e.getMessage());
            channelPayOrderContext.setProcessStatus(Boolean.FALSE);
        }
    }

    private String getPayType(PayWayDO payWayDO) {
        PayEnums.PAY_TYPE payType = PayEnums.PAY_TYPE.fromByCode(payWayDO.getType());
        if (Objects.isNull(payType)) return "";
        switch (payType) {
            case WECHAT:
                return "WECHATPAY";
            case ALIPAY:
                return "ALIPAY";
        }
        return "";
    }

    @Override
    public void queryChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonQueryChannelPayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void closeChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
    }

    @Override
    public void queryChannelClosePayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
    }

    @Override
    public void refundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        commonRefundChannelPayOrder(channelRefundPayOrderContext);
    }

    @Override
    public void queryRefundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        commonQueryRefundChannelPayOrder(channelRefundPayOrderContext);
    }

    @Override
    public boolean refundApply(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        return true;
    }

    @Override
    public CommonResult<String> channelOrderCode(ChannelPayOrderContext channelPayOrderContext) {
        return CommonResult.success();
    }

}
